﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;

namespace socket服务器端
{
    public partial class MainWindowViewModel : ObservableObject
    {
        /// <summary>
        /// IP地址
        /// </summary>
        [ObservableProperty]
        string iPAddressInfo;

        /// <summary>
        /// 端口号
        /// </summary>
        [ObservableProperty]
        string portInfo;

        /// <summary>
        /// 日志记录
        /// </summary>
        [ObservableProperty]
        public ObservableCollection<LogInfo> logList = new ObservableCollection<LogInfo>();

        /// <summary>
        /// 发送消息
        /// </summary>
        [ObservableProperty]
        string sendInfo;

        /// <summary>
        /// 客户端socket集合
        /// </summary>
        ObservableCollection<Socket> ClientSocketList = new ObservableCollection<Socket>();

        /// <summary>
        /// 启动socket
        /// </summary>
        [RelayCommand]
        void StartSocket()
        {
            if (string.IsNullOrEmpty(IPAddressInfo) || string.IsNullOrEmpty(PortInfo))
            {
                return;
            }


            // 创建Socket
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


            try
            {
                // 绑定端口ip
                socket.Bind(new IPEndPoint(IPAddress.Parse(IPAddressInfo), int.Parse(PortInfo)));

                // 开启监听
                socket.Listen(10);
            }
            catch (Exception ex)
            {
                MessageBox.Show("启动socket失败，请重新尝试");
                return;
            }
            
            // 开始接收客户端的链接
            ThreadPool.QueueUserWorkItem(new WaitCallback(AcceptClientConnet), socket);

            
        }

        /// <summary>
        /// 接收客户端的连接
        /// </summary>
        /// <param name="socket"></param>
        public void AcceptClientConnet(object socket)
        {
            Socket newSocket = socket as Socket;

            AppendText("服务器端开始接收客户端的连接");

            while (true)
            {
                Socket acceptSocket = newSocket.Accept();

                ClientSocketList.Add(acceptSocket);

                AppendText($"客户端:{acceptSocket.RemoteEndPoint.ToString()}已连接上");


                // 接收客户端发送的消息
                ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveData), acceptSocket);
            }
        }

        /// <summary>
        /// 接收客户端发送的数据
        /// </summary>
        public void ReceiveData(object socket)
        {
            Socket clientSocket = socket as Socket;
            byte[] data = new byte[1024 * 1024];

            while (true)
            {
                int len = 0;

                try
                {
                    len = clientSocket.Receive(data, 0, data.Length, SocketFlags.None);
                }
                catch (Exception ex)
                {
                    AppendText($"客户端:{clientSocket.RemoteEndPoint.ToString()},{ex.Message}");

                    // 关闭socket连接
                    StopConnect(clientSocket);
                    return;
                }

                if (len <= 0)
                {
                    AppendText($"客户端:{clientSocket.RemoteEndPoint.ToString()}正常退出");
                    ClientSocketList.Remove(clientSocket);
                    return;
                }

                string str = Encoding.Default.GetString(data, 0, len);
                AppendText($"接收到客户端:{clientSocket.RemoteEndPoint.ToString()},消息为:{str}");

            }
        }

        /// <summary>
        /// 更新日志消息
        /// </summary>
        /// <param name="str"></param>
        public void AppendText(string str)
        {
            // 修改UI不能跨线程执行
            Application.Current.Dispatcher.BeginInvoke(() =>
            {
                LogList.Add(new LogInfo() { Time = DateTime.Now.ToString(), Info = str });
            });
            
        }

        
        /// <summary>
        /// 关闭对应socket连接
        /// </summary>
        /// <param name="socket"></param>
        private void StopConnect(Socket socket)
        {
            try
            {
                if (socket.Connected)
                {
                    socket.Shutdown(SocketShutdown.Both);
                    socket.Close(100);
                }
            }
            catch (Exception ex)
            {

                throw;
            }
            
        }


        /// <summary>
        /// 发送信息
        /// </summary>
        [RelayCommand]
        void Send()
        {
            foreach (var clientSocket in ClientSocketList)
            {
                if (clientSocket.Connected)
                {
                    // 原始数据
                    byte[] data = Encoding.Default.GetBytes(SendInfo);

                    // 最终添加协议的头部字节数组
                    byte[] result = new byte[data.Length + 1];

                    // 设置头部字节 (1代表字符串)
                    result[0] = 1;

                    // 把原始的数据放到最终的字节数组中
                    Buffer.BlockCopy(data, 0, result, 1, data.Length);

                    // 发送 最终添加协议的头部字节数组
                    clientSocket.Send(result, 0, result.Length, SocketFlags.None);


                    // 清空发送区
                    SendInfo = string.Empty;
                }
            }
        }

        /// <summary>
        /// 发送文件
        /// </summary>
        [RelayCommand]
        void SendFile()
        {
            string str = ReadFile.OpenFile();

            byte[] FileContent = Encoding.Default.GetBytes(str);

            byte[] result = new byte[FileContent.Length + 1];

            result[0] = 3;

            Buffer.BlockCopy(FileContent, 0, result, 1, FileContent.Length);

            foreach (var clientSocket in ClientSocketList)
            {
                if (clientSocket.Connected)
                {
                    clientSocket.Send(result, 0, result.Length, SocketFlags.None);
                }
            }
        }


        /// <summary>
        /// 发送闪屏
        /// </summary>
        [RelayCommand]
        void SendFlashScreen()
        {
            foreach (var clientSocket in ClientSocketList)
            {
                if (clientSocket.Connected)
                {
                    byte[] result = new byte[1] { 2 };

                    clientSocket.Send(result, 0, result.Length, SocketFlags.None);
                }
            }
        }
    }
}
